import { Injectable, NestMiddleware, UnauthorizedException, ForbiddenException } from '@nestjs/common'
import { Request, Response, NextFunction } from 'express'
import { JwtService } from '@nestjs/jwt'
import rateLimit from 'express-rate-limit'
import helmet from 'helmet'
import compression from 'compression'
import cors from 'cors'
import { LoggerService } from '../logger/logger.service'
import { UserInfo } from '../decorators/user.decorator'

/**
 * 请求日志中间件
 * 记录所有HTTP请求的详细信息
 */
@Injectable()
export class RequestLoggerMiddleware implements NestMiddleware {
  constructor(private readonly logger: LoggerService) {}

  use(req: Request, res: Response, next: NextFunction): void {
    const startTime = Date.now()
    const { method, originalUrl, ip, headers } = req
    const userAgent = headers['user-agent'] || ''
    const referer = headers.referer || ''
    const requestId = this.generateRequestId()

    // 添加请求ID到请求对象
    req.requestId = requestId

    // 记录请求开始
    this.logger.info('HTTP请求开始', {
      requestId,
      method,
      url: originalUrl,
      ip,
      userAgent,
      referer,
      timestamp: new Date().toISOString()
    })

    // 监听响应结束事件
    res.on('finish', () => {
      const duration = Date.now() - startTime
      const { statusCode } = res
      const contentLength = res.get('content-length') || '0'

      // 记录请求结束
      this.logger.info('HTTP请求结束', {
        requestId,
        method,
        url: originalUrl,
        statusCode,
        duration: `${duration}ms`,
        contentLength: `${contentLength}bytes`,
        ip,
        userAgent
      })

      // 记录慢请求
      if (duration > 5000) {
        this.logger.warn(
          '慢请求检测',
          JSON.stringify({
            requestId,
            method,
            url: originalUrl,
            duration: `${duration}ms`,
            statusCode
          })
        )
      }

      // 记录错误请求
      if (statusCode >= 400) {
        this.logger.error(
          '错误请求',
          JSON.stringify({
            requestId,
            method,
            url: originalUrl,
            statusCode,
            duration: `${duration}ms`,
            ip
          })
        )
      }
    })

    next()
  }

  private generateRequestId(): string {
    return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
  }
}

/**
 * 安全头中间件
 * 设置各种安全相关的HTTP头
 */
@Injectable()
export class SecurityHeadersMiddleware implements NestMiddleware {
  constructor(private readonly logger: LoggerService) {}

  use(req: Request, res: Response, next: NextFunction): void {
    // 设置安全头
    res.setHeader('X-Content-Type-Options', 'nosniff')
    res.setHeader('X-Frame-Options', 'DENY')
    res.setHeader('X-XSS-Protection', '1; mode=block')
    res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin')
    res.setHeader('Permissions-Policy', 'geolocation=(), microphone=(), camera=()')

    // 移除敏感头信息
    res.removeHeader('X-Powered-By')
    res.removeHeader('Server')

    // 在生产环境中设置HSTS
    if (process.env.NODE_ENV === 'production') {
      res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload')
    }

    this.logger.debug('安全头设置完成', {
      url: req.originalUrl,
      method: req.method
    })

    next()
  }
}

/**
 * CORS中间件
 * 处理跨域请求
 */
@Injectable()
export class CorsMiddleware implements NestMiddleware {
  constructor(private readonly logger: LoggerService) {}

  use(req: Request, res: Response, next: NextFunction): void {
    const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',') || ['http://localhost:3000', 'http://localhost:3001']

    const origin = req.headers.origin

    if (origin && allowedOrigins.includes(origin)) {
      res.setHeader('Access-Control-Allow-Origin', origin)
    } else if (process.env.NODE_ENV === 'development') {
      // 开发环境允许所有来源
      res.setHeader('Access-Control-Allow-Origin', '*')
    }

    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS')
    res.setHeader(
      'Access-Control-Allow-Headers',
      'Origin, X-Requested-With, Content-Type, Accept, Authorization, X-API-Key'
    )
    res.setHeader('Access-Control-Allow-Credentials', 'true')
    res.setHeader('Access-Control-Max-Age', '86400') // 24小时

    // 处理预检请求
    if (req.method === 'OPTIONS') {
      this.logger.debug('处理CORS预检请求', {
        origin,
        method: req.method,
        url: req.originalUrl
      })
      res.status(200).end()
      return
    }

    this.logger.debug('CORS处理完成', {
      origin,
      method: req.method,
      url: req.originalUrl
    })

    next()
  }
}

/**
 * 请求体大小限制中间件
 */
@Injectable()
export class BodySizeLimitMiddleware implements NestMiddleware {
  constructor(private readonly logger: LoggerService) {}

  use(req: Request, res: Response, next: NextFunction): void {
    const maxSize = parseInt(process.env.MAX_REQUEST_SIZE || '10485760') // 10MB
    const contentLength = parseInt(req.headers['content-length'] || '0')

    if (contentLength > maxSize) {
      this.logger.warn(
        '请求体过大',
        JSON.stringify({
          contentLength,
          maxSize: maxSize,
          url: req.originalUrl,
          method: req.method,
          ip: req.ip
        })
      )

      res.status(413).json({
        success: false,
        code: 413,
        message: '请求体过大',
        data: null,
        meta: {
          timestamp: new Date().toISOString(),
          maxSize: `${maxSize}bytes`,
          receivedSize: `${contentLength}bytes`
        }
      })
      return
    }

    next()
  }
}

/**
 * IP白名单中间件
 */
@Injectable()
export class IpWhitelistMiddleware implements NestMiddleware {
  private readonly whitelist: string[]

  constructor(private readonly logger: LoggerService) {
    this.whitelist = process.env.IP_WHITELIST?.split(',') || []
  }

  use(req: Request, res: Response, next: NextFunction): void {
    // 如果没有配置白名单，则跳过检查
    if (this.whitelist.length === 0) {
      return next()
    }

    const clientIp = this.getClientIp(req)

    if (!this.isIpAllowed(clientIp)) {
      this.logger.warn(
        'IP地址不在白名单中',
        JSON.stringify({
          ip: clientIp,
          url: req.originalUrl,
          method: req.method,
          userAgent: req.headers['user-agent']
        })
      )

      res.status(403).json({
        success: false,
        code: 403,
        message: 'IP地址不被允许',
        data: null,
        meta: {
          timestamp: new Date().toISOString(),
          ip: clientIp
        }
      })
      return
    }

    this.logger.debug('IP白名单验证通过', {
      ip: clientIp,
      url: req.originalUrl
    })

    next()
  }

  private getClientIp(req: Request): string {
    return (
      (req.headers['x-forwarded-for'] as string) ||
      (req.headers['x-real-ip'] as string) ||
      req.connection.remoteAddress ||
      req.socket.remoteAddress ||
      req.ip ||
      'unknown'
    )
      .split(',')[0]
      .trim()
  }

  private isIpAllowed(ip: string): boolean {
    return this.whitelist.some(allowedIp => {
      if (allowedIp.includes('/')) {
        // CIDR格式
        return this.isIpInCidr(ip, allowedIp)
      } else {
        // 精确匹配
        return ip === allowedIp
      }
    })
  }

  private isIpInCidr(ip: string, cidr: string): boolean {
    // 简单的CIDR检查实现
    // 生产环境建议使用专门的库如 'ip-range-check'
    const [network, prefixLength] = cidr.split('/')
    const networkParts = network.split('.').map(Number)
    const ipParts = ip.split('.').map(Number)
    const prefix = parseInt(prefixLength)

    const networkInt = (networkParts[0] << 24) + (networkParts[1] << 16) + (networkParts[2] << 8) + networkParts[3]
    const ipInt = (ipParts[0] << 24) + (ipParts[1] << 16) + (ipParts[2] << 8) + ipParts[3]
    const mask = (-1 << (32 - prefix)) >>> 0

    return (networkInt & mask) === (ipInt & mask)
  }
}

/**
 * 用户会话中间件
 * 从JWT令牌中提取用户信息（可选）
 */
@Injectable()
export class UserSessionMiddleware implements NestMiddleware {
  constructor(
    private readonly jwtService: JwtService,
    private readonly logger: LoggerService
  ) {}

  use(req: Request, res: Response, next: NextFunction): void {
    const token = this.extractTokenFromHeader(req)

    if (token) {
      try {
        const payload = this.jwtService.verify(token, {
          secret: process.env.JWT_SECRET
        })

        // 构建用户信息（不验证过期时间，只是提取信息）
        const user: UserInfo = {
          id: payload.sub,
          username: payload.username,
          email: payload.email,
          role: payload.role,
          permissions: payload.permissions || [],
          avatar: payload.avatar,
          nickname: payload.nickname,
          status: payload.status,
          createdAt: new Date(payload.createdAt),
          updatedAt: new Date(payload.updatedAt)
        }

        req.user = user

        this.logger.debug('用户会话信息提取成功', {
          userId: user.id,
          username: user.username,
          url: req.originalUrl
        })
      } catch (error) {
        // 令牌无效或过期，但不阻止请求继续
        this.logger.debug('用户会话令牌无效', {
          error: error.message,
          url: req.originalUrl
        })
      }
    }

    next()
  }

  private extractTokenFromHeader(req: Request): string | undefined {
    const [type, token] = req.headers.authorization?.split(' ') ?? []
    return type === 'Bearer' ? token : undefined
  }
}

/**
 * API版本中间件
 * 处理API版本控制
 */
@Injectable()
export class ApiVersionMiddleware implements NestMiddleware {
  constructor(private readonly logger: LoggerService) {}

  use(req: Request, res: Response, next: NextFunction): void {
    // 从头部或URL中获取API版本
    const headerVersion = req.headers['api-version'] as string
    const urlVersion = req.originalUrl.match(/^\/api\/v(\d+)\//)?.[1]

    const version = headerVersion || urlVersion || '1'
    const supportedVersions = ['1', '2']

    if (!supportedVersions.includes(version)) {
      this.logger.warn(
        '不支持的API版本',
        JSON.stringify({
          version,
          supportedVersions,
          url: req.originalUrl,
          method: req.method
        })
      )

      res.status(400).json({
        success: false,
        code: 400,
        message: `不支持的API版本: v${version}`,
        data: null,
        meta: {
          timestamp: new Date().toISOString(),
          supportedVersions: supportedVersions.map(v => `v${v}`)
        }
      })
      return
    }

    // 将版本信息添加到请求对象
    req.apiVersion = version

    // 设置响应头
    res.setHeader('API-Version', version)

    this.logger.debug('API版本验证通过', {
      version,
      url: req.originalUrl
    })

    next()
  }
}

/**
 * 健康检查中间件
 * 为健康检查端点提供快速响应
 */
@Injectable()
export class HealthCheckMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction): void {
    if (req.originalUrl === '/health' || req.originalUrl === '/api/health') {
      res.status(200).json({
        success: true,
        code: 200,
        message: '服务正常运行',
        data: {
          status: 'healthy',
          timestamp: new Date().toISOString(),
          uptime: process.uptime(),
          memory: process.memoryUsage(),
          version: process.env.npm_package_version || '1.0.0'
        },
        meta: {
          timestamp: new Date().toISOString()
        }
      })
      return
    }

    next()
  }
}

/**
 * 中间件配置函数
 */
export const configureMiddleware = (): {
  helmet: any
  compression: any
  rateLimit: any
  cors: any
} => {
  return {
    // Helmet安全中间件
    helmet: helmet({
      contentSecurityPolicy: {
        directives: {
          defaultSrc: ["'self'"],
          styleSrc: ["'self'", "'unsafe-inline'"],
          scriptSrc: ["'self'"],
          imgSrc: ["'self'", 'data:', 'https:']
        }
      },
      hsts: {
        maxAge: 31536000,
        includeSubDomains: true,
        preload: true
      }
    }),

    // 压缩中间件
    compression: compression({
      filter: (req, res) => {
        if (req.headers['x-no-compression']) {
          return false
        }
        return compression.filter(req, res)
      },
      threshold: 1024 // 只压缩大于1KB的响应
    }),

    // 速率限制中间件
    rateLimit: rateLimit({
      windowMs: 15 * 60 * 1000, // 15分钟
      max: 100, // 每个IP最多100个请求
      message: {
        success: false,
        code: 429,
        message: '请求过于频繁，请稍后再试',
        data: null,
        meta: {
          timestamp: new Date().toISOString()
        }
      },
      standardHeaders: true,
      legacyHeaders: false
    }),

    // CORS中间件
    cors: cors({
      origin: (origin, callback) => {
        const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',') || [
          'http://localhost:3000',
          'http://localhost:3001'
        ]

        if (!origin || allowedOrigins.includes(origin)) {
          callback(null, true)
        } else {
          callback(new Error('不被CORS策略允许'))
        }
      },
      credentials: true,
      methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
      allowedHeaders: [
        'Origin',
        'X-Requested-With',
        'Content-Type',
        'Accept',
        'Authorization',
        'X-API-Key',
        'API-Version'
      ]
    })
  }
}

// 类型声明已移至 src/types/express.d.ts
